#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
#include "statemachine.h"

void preLoadSymboltable()
{
				/* Token definitions for keywords:
				 * 
				 * fixed2	100
				 * void		101
				 * int			102
				 * ;			103
				 * {			104
				 * }			105
				 * (			106
				 * )			107				 
				 * +			108
				 * -			109
				 * "*"			110
				 *"/"			111
				 * %			112
				 * &&			113
				 * ||			114
				 * !=			115
				 * ==		116
				 * =			117
				 * <=		118
				 * >=		119
				 * >			120
				 * <			121
				 * .			122
				 * ,			123
				 * if			124
				 * else		125
				 * while		126
				 * input 		127
				 * output	128
				 */
				symbol symbolEntry;
				symbolEntry.lexture[0]  = 'f';
				symbolEntry.lexture[1]  = 'i';
				symbolEntry.lexture[2]  = 'x';
				symbolEntry.lexture[3]  = 'e';
				symbolEntry.lexture[4]  = 'd';
				symbolEntry.lexture[5]  = '2';
				symbolEntry.lexture[6]  = 0;
				symbolEntry.token[0] = 100;
				symbolEntry.value = 0;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = 'v';
				symbolEntry.lexture[1] = 'o';
				symbolEntry.lexture[2] = 'i';
				symbolEntry.lexture[3] = 'd';
				symbolEntry.lexture[4] = 0;
				symbolEntry.token[0] = 101;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = 'i';
				symbolEntry.lexture[1] = 'n';
				symbolEntry.lexture[2] = 't';
				symbolEntry.lexture[3] = 0;
				symbolEntry.token[0] = 102;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = ';';
				symbolEntry.lexture[1] = 0;
				symbolEntry.token[0] = 103;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = '{';
				symbolEntry.token[0] = 104;
				symboltable.push_back(symbolEntry);				
				
				symbolEntry.lexture[0] = '}';
				symbolEntry.token[0] = 105;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = '(';
				symbolEntry.token[0] = 106;
				symboltable.push_back(symbolEntry);				
				
				symbolEntry.lexture[0] = ')';
				symbolEntry.token[0] = 107;
				symboltable.push_back(symbolEntry);			
				
				symbolEntry.lexture[0] = '+';
				symbolEntry.token[0] = 108;
				symboltable.push_back(symbolEntry);			
				
				symbolEntry.lexture[0] = '-';
				symbolEntry.token[0] = 109;
				symboltable.push_back(symbolEntry);			
				
				symbolEntry.lexture[0] = '*';
				symbolEntry.token[0] = 110;
				symboltable.push_back(symbolEntry);			
				
				symbolEntry.lexture[0] = '/';
				symbolEntry.token[0] = 111;
				symboltable.push_back(symbolEntry);			
				
				symbolEntry.lexture[0] = '%';
				symbolEntry.token[0] = 112;
				symboltable.push_back(symbolEntry);			
				
				symbolEntry.lexture[0] = '&';
				symbolEntry.lexture[1] = '&';
				symbolEntry.lexture[2] = 0;
				symbolEntry.token[0] = 113;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = '|';
				symbolEntry.lexture[1] = '|';
				symbolEntry.token[0] = 114;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = '!';
				symbolEntry.lexture[1] = '=';
				symbolEntry.token[0] = 115;
				symboltable.push_back(symbolEntry);		
				
				symbolEntry.lexture[0] = '=';
				symbolEntry.lexture[1] = '=';
				symbolEntry.token[0] = 116;
				symboltable.push_back(symbolEntry);		
				
				symbolEntry.lexture[0] = '=';
				symbolEntry.lexture[1] = 0;
				symbolEntry.token[0] = 117;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = '<';
				symbolEntry.lexture[1] = '=';
				symbolEntry.token[0] = 118;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = '>';
				symbolEntry.lexture[1] = '=';
				symbolEntry.token[0] = 119;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = '>';
				symbolEntry.lexture[1] = 0;
				symbolEntry.token[0] = 120;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = '<';
				symbolEntry.token[0] = 121;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = '.';
				symbolEntry.token[0] = 122;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = ',';
				symbolEntry.token[0] = 123;
				symboltable.push_back(symbolEntry);

				symbolEntry.lexture[0] = 'i';
				symbolEntry.lexture[1] = 'f';
				symbolEntry.lexture[2] = 0;
				symbolEntry.token[0] = 124;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = 'e';
				symbolEntry.lexture[1] = 'l';
				symbolEntry.lexture[2] = 's';
				symbolEntry.lexture[3] = 'e';
				symbolEntry.lexture[4] = 0;
				symbolEntry.token[0] = 125;
				symboltable.push_back(symbolEntry);	
				
				symbolEntry.lexture[0] = 'w';
				symbolEntry.lexture[1] = 'h';
				symbolEntry.lexture[2] = 'i';
				symbolEntry.lexture[3] = 'l';
				symbolEntry.lexture[4] = 'e';
				symbolEntry.lexture[5] = 0;
				symbolEntry.token[0] = 126;
				symboltable.push_back(symbolEntry);	
				
				symbolEntry.lexture[0] = 'i';
				symbolEntry.lexture[1] = 'n';
				symbolEntry.lexture[2] = 'p';
				symbolEntry.lexture[3] = 'u';
				symbolEntry.lexture[4] = 't';
				symbolEntry.lexture[5] = 0;
				symbolEntry.token[0] = 127;
				symboltable.push_back(symbolEntry);	
				
				symbolEntry.lexture[0] = 'o';
				symbolEntry.lexture[1] = 'u';
				symbolEntry.lexture[2] = 't';
				symbolEntry.lexture[3] = 'p';
				symbolEntry.lexture[4] = 'u';
				symbolEntry.lexture[5] = 't';
				symbolEntry.lexture[6] = 0;
				symbolEntry.token[0] = 128;
				symboltable.push_back(symbolEntry);					
}


int main ( int argc, char *argv[] )
{
  if ( argc != 3 ) // argc should be 2 for correct execution
  {
	  cout<<"usage: "<< argv[0] <<" <filename in> <filename out>\n";
  }
  else {
    // We assume argv[1] is a filename to open
    ifstream the_file ( argv[1] );
    // Always check to see if file opening succeeded
    if ( !the_file.is_open() )
      cout<<"Could not open file\n";
    else {
      ofstream lexemeFile("lexemeArray.txt", ios_base::binary);
      preLoadSymboltable();
      char x;
      unsigned char state;
      string buffer = "";
	  ofstream symboltableFile(argv[2]);
      // the_file.get ( x ) returns false if the end of the file
      //  is reached or an error occurs
      state = 1;
      buffer = "";
      while ( the_file.get ( x ) )
      {        
      	if (statetable[state][BU] == 'y')
		// spol char pointer 1 tilbage
		{
			the_file.seekg(-1, ios::cur);
			buffer.erase(buffer.end()-1);
		}
		if (statetable[state][accept] == 'y')
		{
			int lextureInSymboltable = -1;
			// search if token exists in symboltable
			vector<symbol>::iterator it;
			int i = 0;
			//buffer.erase(buffer.end()-1);
			for (it=symboltable.begin(); it<symboltable.end(); it++)
			{
				if (strcmp(symboltable[i].lexture, buffer.data()) == 0)
				{
					lextureInSymboltable = i;
				}
				i++;
				
			}
			// ny post i sym tabel af typen state

			if (lextureInSymboltable == -1) // Tjekker om symbol IKKE findes i tabellen
			{
			/*	if(symboltable.size() == symboltable.max_size())
				{
					symboltable.resize(2*symboltable.max_size());	
				}*/
				symbol symbolEntry;
				memcpy(symbolEntry.lexture, buffer.c_str(), buffer.length()+1);
				symbolEntry.token[0] = state;
				symbolEntry.value = atoi(buffer.c_str());
				symboltable.push_back(symbolEntry);
				buffer = "";
				// Add corresponding entry in symbol table to lexeme array
			//	lexemeFile.put((char)(symboltable.size()-1));
				lexemeFile << (symboltable.size()-1) << endl;
			//	lexemeArray.push_back(symboltable.size()-1);
			}
			else 
			{
				//Add corresponding entry in symbol table to lexeme array
			//	lexemeFile.write((char)lextureInSymboltable);
				lexemeFile << lextureInSymboltable << endl;
			//	lexemeArray.push_back(lextureInSymboltable);
				buffer="";
			}
		}
		buffer.append(1,x);
		//if (statetable[state][in_keyword_list] != 'd')
		//	// check buffer imod k_liste
		//	{
		//		  state = statetable[state][not_in_keyword_list];
		//		  for(int cntr = 0; cntr < N_keywords; cntr++)
		//		  {
		//		    if(keyword_list[cntr] == buffer)
		//		    {
		//		    	state = statetable[state][in_keyword_list];
		//				break;
		//		    }
		//		  }
		//	}
		//else
		//{
		
	      	if (('0' <= x) && (x <= '9')) // is digit
			{	
				state = statetable[state][digit];
			}
	      	else if ( ('a' <= (x | 0x20)) && ((x | 0x20) <= 'z')) //is letter
	      	{
				state = statetable[state][letter];				
			}
			else switch (x) {
				case '_':
						state = statetable[state][underscore];
						break;
				case '{':
						state = statetable[state][tuborg_B];
						break;   
				case '}':
						state = statetable[state][tuborg_E];
						break;
				case '(':
						state = statetable[state][paranthesis_B];
						break;
				case ')':
						state = statetable[state][paranthesis_E];
						break;
				case '+':
						state = statetable[state][plus];
						break;
				case '-':
						state = statetable[state][minus];
						break;
				case '*':
						state = statetable[state][multiply];
						break;
				case '/':
						state = statetable[state][front_slash];
						break;
				case '%':
						state = statetable[state][modulo];
						break;
				case '&':
						state = statetable[state][single_and];
						break;
				case '|':
						state = statetable[state][pipe];
						break;
				case '!':
						state = statetable[state][exclamation];
						break;
				case '<':
						state = statetable[state][less_than];
						break;
				case '>':
						state = statetable[state][greater_than];
						break;
				case '=':
						state = statetable[state][equals];
						break;
				case '.':
						state = statetable[state][dot];
						break;
				case ';':
						state = statetable[state][semicolon];
						break;
				case ',':
						state = statetable[state][comma];
						break;
				case '\r':
						state = statetable[state][whitespace];
						break;
				case '\n':
						state = statetable[state][whitespace];
						break;
				case ' ':
						state = statetable[state][whitespace];
						break;
				case '\t':
						state = statetable[state][whitespace];
						break;
				default:
						state = statetable[state][AE];
				}

      	if (state==1 || state==30)
      	{
      		//buffer.erase(buffer.end()-1);
      		the_file.seekg(-1, ios::cur);
      		buffer = "";
      	}
       else if (state==29)
      	{
      //		the_file.seekg(-1, ios::cur);
     		buffer = "";
     	}
     	else if (state == 28)
     	{
     		printf("Error state");
     	}

	//	cout<< x;
		//}
    // the_file is closed implicitly here
	  }
		int i = 0;
		vector<symbol>::iterator it;	
		symboltableFile << "\"Lexture\"" << "," << "\"Token\"" << "," << "\"Value\"" << endl;
	
		for (it=symboltable.begin(); it<symboltable.end(); it++)
		{
			symboltableFile << "\"" << symboltable[i].lexture << "\"" << "," << "\"" << (int)symboltable[i].token[0] << "\"" << "," << symboltable[i].value << endl;
			i++;
		}
	}
  }
  return 0;
}